/*
 * @(#)com.cloud.food.service.wx 2020/2/16 02:16
 * @Author <a href="mailto:xyqierkang@gmail.com">ErKang Qi</a>
 * @Blog：https://www.qekang.com
 * Copyright (c) 2019-2020 Shanghai
 * All rights reserved.

 * This software is the confidential and proprietary information of
 * You shall not disclose such Confidential Information and shall use
 * it only in accordance with the terms of the license agreement
 */
package com.cloud.lan.service.tx.wx;

import com.cloud.lan.entity.base.BaseResponse;
import com.cloud.lan.entity.base.exceptions.BaseException;
import com.cloud.lan.entity.constant.WxDataConstant;
import com.cloud.lan.service.tx.wx.config.WxMaConfiguration;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.stereotype.Service;

import java.security.AlgorithmParameters;
import java.security.Security;
import java.util.Arrays;

import javax.annotation.Resource;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.symmetric.AES;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;

import static java.nio.charset.StandardCharsets.UTF_8;

/**
 * *********************************************************
 *
 * @Author <a href="mailto:xyqierkang@gmail.com">ErKang Qi</a>
 * @Date Created in $ $
 * @Title $.java
 * <p>Description: [ TODO ] </p>
 * <p>Blog: https://www.qekang.com</p>
 * <p>Inc:  </p>
 * <p>Copyright:    </p>
 * <p>Department: Product development </p>
 * *********************************************************
 */
@Slf4j
@Service
public class WxInitService {

    @Resource
    WxMaConfiguration wxMaConfiguration;

    public WxMaJscode2SessionResult getSession(String wxAuthCode) {
        WxMaService wxService = wxMaConfiguration.getMaService(WxDataConstant.APPID);
        try {
            WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(wxAuthCode);
            log.info(session.getSessionKey());
            log.info(session.getOpenid());
            return session;
        } catch (WxErrorException e) {
            throw new BaseException(BaseResponse.ERROR, e.getMessage());
        }
    }

    public static String decryptData(String sessionKey, String encryptedData, String iv) {
        try {
            AES cipher =
                    new AES(
                            Mode.CBC.name(),
                            "PKCS5Padding",
                            Base64.decode(sessionKey),
                            Base64.decode(iv));
            byte[] data = cipher.decrypt(Base64.decode(encryptedData));
            return StrUtil.str(data, UTF_8);
        } catch (Exception e) {
            log.error(
                    String.format(
                            "微信解密数据错误 sessionKey:%s, encryptedData:%s, iv:%s",
                            sessionKey, encryptedData, iv),
                    e);
            throw new BaseException(BaseResponse.ERROR, e.getMessage());
        }
    }

    public static void main(String[] args) {
        String s =
                decryptData(
                        "6MDbK4VZpKOiKVRc0x3YaA==",
                        "DHUEE8T5ixuyrDkGxKRDgd5zzHdqGQRlqEpqEyj0BGW/aT0bEuU6wB0O2SweTnUPjo8yX4Wllz/0qKFOnuCzYu UsJkrNrl/bVXuBHGSnlxbC5BLuJ/w0L6aE8" +
                                " 8k8zQCvBAkHlP0acMkkvTBZSiS0PxSg " +
                                "4OmoeayUCINaHg0j6ram4RnBaIDuGIBSJZEaM0LwgIqxzbtyRXLkab8aw50bdRiK6sdoG5HuWkl0o7pTnbOuA1gsgWA3ugIsDXZxrbdvCvQaNAad " +
                                "PVDS79YYiHuQCfzlAdxXUsSMqHUqS3/PSP8R3DacjoxdXDs0If1vFWB C2ii371sbU0eChRYnq5Mt vwFJ1byHBDo6Ddl " +
                                "6L2YGTKSDF2f51U5ebQuCG0IsrjlqK7 Byc0ELr1u Iw==",
                        "Nkynd0bE8UD8fZSdkEB2 g==");
        System.out.println(s);
    }

    public WxMaUserInfo info(String sessionKey, String encryptedData, String iv) {
        final WxMaService wxService = wxMaConfiguration.getMaService(WxDataConstant.APPID);
        try {
//            String EncryptedData = URLEncoder.encode(encryptedData, "UTF-8").replace("%3D", "=").replace("%2F", "/");
//            String Iv = URLEncoder.encode(iv, "UTF-8").replace("%3D", "=").replace("%2F", "/");
            WxMaUserInfo userInfo = wxService.getUserService().getUserInfo(sessionKey, encryptedData, iv);
            return userInfo;
        } catch (Exception e) {
            throw new BaseException(BaseResponse.ERROR, e.getMessage());
        }
    }

    public String encryptedData(String sessionKey, String encryptedData, String iv) {
        try {
            byte[] encryptedDataBytes = org.apache.tomcat.util.codec.binary.Base64.decodeBase64(encryptedData);
            byte[] ivBytes = org.apache.tomcat.util.codec.binary.Base64.decodeBase64(iv);
            byte[] keyBytes = org.apache.tomcat.util.codec.binary.Base64.decodeBase64(sessionKey);
            int base = 16;
            if (keyBytes.length % base != 0) {
                int groups = keyBytes.length / base + (keyBytes.length % base != 0 ? 1 : 0);
                byte[] temp = new byte[groups * base];
                Arrays.fill(temp, (byte) 0);
                System.arraycopy(keyBytes, 0, temp, 0, keyBytes.length);
                keyBytes = temp;
            }
            Security.addProvider(new BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC");
            SecretKeySpec spec = new SecretKeySpec(keyBytes, "AES");
            AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
            parameters.init(new IvParameterSpec(ivBytes));
            cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化
            String result = new String(cipher.doFinal(encryptedDataBytes), "UTF-8");
            return result;
        } catch (Exception e) {
            log.error(
                    String.format(
                            "微信解密数据错误 sessionKey:%s, encryptedData:%s, iv:%s",
                            sessionKey, encryptedData, iv),
                    e);
            throw new BaseException(BaseResponse.ERROR, e.getMessage());
        }
    }
}
